/*
 * Copyright 2017-Present, Redis Ltd. and Contributors
 * All rights reserved.
 *
 * Licensed under the MIT License.
 *
 * This file contains contributions from third-party contributors
 * licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.lettuce.core.cluster.api.async;

import java.util.List;

import io.lettuce.core.KeyValue;
import io.lettuce.core.LMPopArgs;
import io.lettuce.core.LMoveArgs;
import io.lettuce.core.LPosArgs;
import io.lettuce.core.output.ValueStreamingChannel;

/**
 * Asynchronous executed commands on a node selection for Lists.
 *
 * @param <K> Key type.
 * @param <V> Value type.
 * @author Mark Paluch
 * @since 4.0
 * @generated by io.lettuce.apigenerator.CreateAsyncNodeSelectionClusterApi
 */
public interface NodeSelectionListAsyncCommands<K, V> {

    /**
     * Atomically returns and removes the first/last element (head/tail depending on the where from argument) of the list stored
     * at source, and pushes the element at the first/last element (head/tail depending on the whereto argument) of the list
     * stored at destination. When source is empty, Redis will block the connection until another client pushes to it or until
     * timeout is reached.
     *
     * @param source the source key.
     * @param destination the destination type: key.
     * @param args command arguments to configure source and destination directions.
     * @param timeout the timeout in seconds.
     * @return V bulk-string-reply the element being popped and pushed.
     * @since 6.1
     */
    AsyncExecutions<V> blmove(K source, K destination, LMoveArgs args, long timeout);

    /**
     * Atomically returns and removes the first/last element (head/tail depending on the where from argument) of the list stored
     * at source, and pushes the element at the first/last element (head/tail depending on the whereto argument) of the list
     * stored at destination. When source is empty, Redis will block the connection until another client pushes to it or until
     * timeout is reached.
     *
     * @param source the source key.
     * @param destination the destination type: key.
     * @param args command arguments to configure source and destination directions.
     * @param timeout the timeout in seconds.
     * @return V bulk-string-reply the element being popped and pushed.
     * @since 6.1.3
     */
    AsyncExecutions<V> blmove(K source, K destination, LMoveArgs args, double timeout);

    /**
     * Remove and get the first/last elements in a list, or block until one is available.
     *
     * @param timeout the timeout in seconds.
     * @param args the additional command arguments.
     * @param keys the keys.
     * @return KeyValue&lt;K,V&gt; array-reply specifically. {@code null} when {@code key} does not exist or the timeout was
     *         exceeded.
     * @since 6.2
     */
    AsyncExecutions<KeyValue<K, List<V>>> blmpop(long timeout, LMPopArgs args, K... keys);

    /**
     * Remove and get the first/last elements in a list, or block until one is available.
     *
     * @param timeout the timeout in seconds.
     * @param args the additional command arguments.
     * @param keys the keys.
     * @return KeyValue&lt;K,V&gt; array-reply specifically. {@code null} when {@code key} does not exist or the timeout was
     *         exceeded.
     * @since 6.2
     */
    AsyncExecutions<KeyValue<K, List<V>>> blmpop(double timeout, LMPopArgs args, K... keys);

    /**
     * Remove and get the first element in a list, or block until one is available.
     *
     * @param timeout the timeout in seconds.
     * @param keys the keys.
     * @return KeyValue&lt;K,V&gt; array-reply specifically:
     *
     *         A {@code null} multi-bulk when no element could be popped and the timeout expired. A two-element multi-bulk with
     *         the first element being the name of the key where an element was popped and the second element being the value of
     *         the popped element.
     */
    AsyncExecutions<KeyValue<K, V>> blpop(long timeout, K... keys);

    /**
     * Remove and get the first element in a list, or block until one is available.
     *
     * @param timeout the timeout in seconds.
     * @param keys the keys.
     * @return KeyValue&lt;K,V&gt; array-reply specifically:
     *
     *         A {@code null} multi-bulk when no element could be popped and the timeout expired. A two-element multi-bulk with
     *         the first element being the name of the key where an element was popped and the second element being the value of
     *         the popped element.
     * @since 6.1.3
     */
    AsyncExecutions<KeyValue<K, V>> blpop(double timeout, K... keys);

    /**
     * Remove and get the last element in a list, or block until one is available.
     *
     * @param timeout the timeout in seconds.
     * @param keys the keys.
     * @return KeyValue&lt;K,V&gt; array-reply specifically:
     *
     *         A {@code null} multi-bulk when no element could be popped and the timeout expired. A two-element multi-bulk with
     *         the first element being the name of the key where an element was popped and the second element being the value of
     *         the popped element.
     */
    AsyncExecutions<KeyValue<K, V>> brpop(long timeout, K... keys);

    /**
     * Remove and get the last element in a list, or block until one is available.
     *
     * @param timeout the timeout in seconds.
     * @param keys the keys.
     * @return KeyValue&lt;K,V&gt; array-reply specifically:
     *
     *         A {@code null} multi-bulk when no element could be popped and the timeout expired. A two-element multi-bulk with
     *         the first element being the name of the key where an element was popped and the second element being the value of
     *         the popped element.
     * @since 6.1.3
     */
    AsyncExecutions<KeyValue<K, V>> brpop(double timeout, K... keys);

    /**
     * Pop a value from a list, push it to another list and return it; or block until one is available.
     *
     * @param timeout the timeout in seconds.
     * @param source the source key.
     * @param destination the destination type: key.
     * @return V bulk-string-reply the element being popped from {@code source} and pushed to {@code destination}. If
     *         {@code timeout} is reached, a.
     */
    AsyncExecutions<V> brpoplpush(long timeout, K source, K destination);

    /**
     * Pop a value from a list, push it to another list and return it; or block until one is available.
     *
     * @param timeout the timeout in seconds.
     * @param source the source key.
     * @param destination the destination type: key.
     * @return V bulk-string-reply the element being popped from {@code source} and pushed to {@code destination}. If
     *         {@code timeout} is reached, a.
     * @since 6.1.3
     */
    AsyncExecutions<V> brpoplpush(double timeout, K source, K destination);

    /**
     * Get an element from a list by its index.
     *
     * @param key the key.
     * @param index the index type: long.
     * @return V bulk-string-reply the requested element, or {@code null} when {@code index} is out of range.
     */
    AsyncExecutions<V> lindex(K key, long index);

    /**
     * Insert an element before or after another element in a list.
     *
     * @param key the key.
     * @param before the before.
     * @param pivot the pivot.
     * @param value the value.
     * @return Long integer-reply the length of the list after the insert operation, or {@code -1} when the value {@code pivot}
     *         was not found.
     */
    AsyncExecutions<Long> linsert(K key, boolean before, V pivot, V value);

    /**
     * Get the length of a list.
     *
     * @param key the key.
     * @return Long integer-reply the length of the list at {@code key}.
     */
    AsyncExecutions<Long> llen(K key);

    /**
     * Atomically returns and removes the first/last element (head/tail depending on the where from argument) of the list stored
     * at source, and pushes the element at the first/last element (head/tail depending on the whereto argument) of the list
     * stored at destination.
     *
     * @param source the source key.
     * @param destination the destination type: key.
     * @param args command arguments to configure source and destination directions.
     * @return V bulk-string-reply the element being popped and pushed.
     * @since 6.1
     */
    AsyncExecutions<V> lmove(K source, K destination, LMoveArgs args);

    /**
     * Remove and get the first/last elements in a list.
     *
     * @param args the additional command arguments.
     * @param keys the keys.
     * @return KeyValue&lt;K,V&gt; array-reply specifically. {@code null} when {@code key} does not exist.
     * @since 6.2
     */
    AsyncExecutions<KeyValue<K, List<V>>> lmpop(LMPopArgs args, K... keys);

    /**
     * Remove and get the first element in a list.
     *
     * @param key the key.
     * @return V bulk-string-reply the value of the first element, or {@code null} when {@code key} does not exist.
     */
    AsyncExecutions<V> lpop(K key);

    /**
     * Remove and get the first {@code count} elements in a list.
     *
     * @param key the key.
     * @param count the number of elements to return.
     * @return @return List&lt;V&gt; array-reply list of the first {@code count} elements, or {@code null} when {@code key} does
     *         not exist.
     * @since 6.1
     */
    AsyncExecutions<List<V>> lpop(K key, long count);

    /**
     * Return the index of matching elements inside a Redis list. By default, when no options are given, it will scan the list
     * from head to tail, looking for the first match of "element". If the element is found, its index (the zero-based position
     * in the list) is returned. Otherwise, if no match is found, {@code null} is returned. The returned elements indexes are
     * always referring to what {@link #lindex(java.lang.Object, long)} would return. So first element from head is {@code 0},
     * and so forth.
     *
     * @param key the key.
     * @param value the element to search for.
     * @return V integer-reply representing the matching element, or null if there is no match.
     * @since 5.3.2
     */
    AsyncExecutions<Long> lpos(K key, V value);

    /**
     * Return the index of matching elements inside a Redis list. By default, when no options are given, it will scan the list
     * from head to tail, looking for the first match of "element". If the element is found, its index (the zero-based position
     * in the list) is returned. Otherwise, if no match is found, {@code null} is returned. The returned elements indexes are
     * always referring to what {@link #lindex(java.lang.Object, long)} would return. So first element from head is {@code 0},
     * and so forth.
     *
     * @param key the key.
     * @param value the element to search for.
     * @param args command arguments to configure{@code FIRST} and {@code MAXLEN} options.
     * @return V integer-reply representing the matching element, or null if there is no match.
     * @since 5.3.2
     */
    AsyncExecutions<Long> lpos(K key, V value, LPosArgs args);

    /**
     * Return the index of matching elements inside a Redis list using the {@code COUNT} option. By default, when no options are
     * given, it will scan the list from head to tail, looking for the first match of "element". The returned elements indexes
     * are always referring to what {@link #lindex(java.lang.Object, long)} would return. So first element from head is
     * {@code 0}, and so forth.
     *
     * @param key the key.
     * @param value the element to search for.
     * @param count limit the number of matches.
     * @return V integer-reply representing the matching elements, or empty if there is no match.
     * @since 5.3.2
     */
    AsyncExecutions<List<Long>> lpos(K key, V value, int count);

    /**
     * Return the index of matching elements inside a Redis list using the {@code COUNT} option. By default, when no options are
     * given, it will scan the list from head to tail, looking for the first match of "element". The returned elements indexes
     * are always referring to what {@link #lindex(java.lang.Object, long)} would return. So first element from head is
     * {@code 0}, and so forth.
     *
     * @param key the key.
     * @param value the element to search for.
     * @param count limit the number of matches.
     * @param args command arguments to configure{@code FIRST} and {@code MAXLEN} options.
     * @return V integer-reply representing the matching elements, or empty if there is no match.
     * @since 5.3.2
     */
    AsyncExecutions<List<Long>> lpos(K key, V value, int count, LPosArgs args);

    /**
     * Prepend one or multiple values to a list.
     *
     * @param key the key.
     * @param values the value.
     * @return Long integer-reply the length of the list after the push operations.
     */
    AsyncExecutions<Long> lpush(K key, V... values);

    /**
     * Prepend values to a list, only if the list exists.
     *
     * @param key the key.
     * @param values the values.
     * @return Long integer-reply the length of the list after the push operation.
     */
    AsyncExecutions<Long> lpushx(K key, V... values);

    /**
     * Get a range of elements from a list.
     *
     * @param key the key.
     * @param start the start type: long.
     * @param stop the stop type: long.
     * @return List&lt;V&gt; array-reply list of elements in the specified range.
     */
    AsyncExecutions<List<V>> lrange(K key, long start, long stop);

    /**
     * Get a range of elements from a list.
     *
     * @param channel the channel.
     * @param key the key.
     * @param start the start type: long.
     * @param stop the stop type: long.
     * @return Long count of elements in the specified range.
     */
    AsyncExecutions<Long> lrange(ValueStreamingChannel<V> channel, K key, long start, long stop);

    /**
     * Remove elements from a list.
     *
     * @param key the key.
     * @param count the count type: long.
     * @param value the value.
     * @return Long integer-reply the number of removed elements.
     */
    AsyncExecutions<Long> lrem(K key, long count, V value);

    /**
     * Set the value of an element in a list by its index.
     *
     * @param key the key.
     * @param index the index type: long.
     * @param value the value.
     * @return String simple-string-reply.
     */
    AsyncExecutions<String> lset(K key, long index, V value);

    /**
     * Trim a list to the specified range.
     *
     * @param key the key.
     * @param start the start type: long.
     * @param stop the stop type: long.
     * @return String simple-string-reply.
     */
    AsyncExecutions<String> ltrim(K key, long start, long stop);

    /**
     * Remove and get the last element in a list.
     *
     * @param key the key.
     * @return V bulk-string-reply the value of the last element, or {@code null} when {@code key} does not exist.
     */
    AsyncExecutions<V> rpop(K key);

    /**
     * Remove and get the last {@code count} elements in a list.
     *
     * @param key the key.
     * @param count the number of elements to return.
     * @return List&lt;V&gt; array-reply list of the last {@code count} elements, or {@code null} when {@code key} does not
     *         exist.
     * @since 6.1
     */
    AsyncExecutions<List<V>> rpop(K key, long count);

    /**
     * Remove the last element in a list, append it to another list and return it.
     *
     * @param source the source key.
     * @param destination the destination type: key.
     * @return V bulk-string-reply the element being popped and pushed.
     */
    AsyncExecutions<V> rpoplpush(K source, K destination);

    /**
     * Append one or multiple values to a list.
     *
     * @param key the key.
     * @param values the value.
     * @return Long integer-reply the length of the list after the push operation.
     */
    AsyncExecutions<Long> rpush(K key, V... values);

    /**
     * Append values to a list, only if the list exists.
     *
     * @param key the key.
     * @param values the values.
     * @return Long integer-reply the length of the list after the push operation.
     */
    AsyncExecutions<Long> rpushx(K key, V... values);

}
